home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1993-12-23 | 17.2 KB | 703 lines |
- IMPLEMENTATION MODULE dir;
- __IMP_SWITCHES__
- #ifdef HM2
- #ifdef __LONG_WHOLE__
- (*$!i+: Modul muss mit $i- uebersetzt werden! *)
- (*$!w+: Modul muss mit $w- uebersetzt werden! *)
- #else
- (*$!i-: Modul muss mit $i+ uebersetzt werden! *)
- (*$!w-: Modul muss mit $w+ uebersetzt werden! *)
- #endif
- #endif
- (*****************************************************************************)
- (* Basiert auf der MiNTLIB von Eric R. Smith und anderen *)
- (*---------------------------------------------------------------------------*)
- (* 07-Nov-93, Holger Kleinschmidt *)
- (*****************************************************************************)
-
- VAL_INTRINSIC
- CAST_IMPORT
- PTR_ARITH_IMPORT
-
- FROM SYSTEM IMPORT
- (* TYPE *) ADDRESS,
- (* PROC *) ADR, TSIZE;
-
- FROM PORTAB IMPORT
- (* TYPE *) SIGNEDWORD, UNSIGNEDWORD, SIGNEDLONG, UNSIGNEDLONG, WORDSET;
-
- FROM types IMPORT
- (* CONST*) EOS, NULL, DDIRSEP, PATHMAX,
- (* TYPE *) sizeT, StrPtr, StrRange, PathName;
-
- FROM MEMBLK IMPORT
- (* PROC *) memalloc, memdealloc;
-
- FROM OSCALLS IMPORT
- (* PROC *) Dcreate, Fchmod, Ddelete, Dgetdrv, Dsetdrv, Dsetpath, Dopendir,
- Dreaddir, Drewinddir, Dclosedir, Dpathconf, Fdelete, Flink,
- Fsymlink, Freadlink, Frename;
-
- FROM ctype IMPORT
- (* PROC *) tocard;
-
- FROM cstr IMPORT
- (* PROC *) AssignM2ToC, strcmp;
-
- FROM pSTRING IMPORT
- (* PROC *) SLEN, ASSIGN, APPEND, EQUAL, LOWER;
-
- IMPORT e;
-
- FROM DosSystem IMPORT
- (* PROC *) MiNTVersion;
-
- FROM DosSupport IMPORT
- (* CONST*) FINDALL, XDECR, DINCR,
- (* TYPE *) DTA, FileAttributes, FileAttribute,
- (* PROC *) CompletePath, DosToUnix, UnixToDos, FindFirst, FindNext;
-
- FROM file IMPORT
- (* CONST*) fOK,
- (* TYPE *) modeT,
- (* PROC *) access;
-
- FROM pSTORAGE IMPORT
- (* PROC *) ALLOCATE, DEALLOCATE;
-
- (*==========================================================================*)
-
- TYPE
- TOSDIRPtr = POINTER TO TOSDIRType;
-
- TOSDIRState = (STARTSEARCH, INSEARCH, NMFILE);
- TOSDIRType = RECORD
- status : TOSDIRState;
- dta : DTA;
- dirname : PathName;
- dirent : DirentRec;
- dname : ARRAY [0..13] OF CHAR;
- END;
-
- CONST
- (* Absicherung gegen ``unendlich'' grosse Datei- und Pfadnamen *)
- MaxPathAlloc = 2047;
-
- TYPE
- PathBuf = ARRAY [0..MaxPathAlloc] OF CHAR;
-
- MiNTDIRPtr = POINTER TO MiNTDIRType;
-
- MiNTDIRType = RECORD
- dsize : UNSIGNEDLONG; (* (Tatsaechliche) Groesse des RECORDs *)
- bsize : UNSIGNEDLONG; (* (Tatsaechliche) Groesse von 'dino' + 'dname' *)
- dhandle : UNSIGNEDLONG;
- dirent : DirentRec;
- dino : UNSIGNEDLONG;
- dname : PathBuf;
- (* Fuer 'dname' wird nur soweit noetig Speicher angefordert. *)
- END;
-
- VAR
- MiNT : BOOLEAN;
-
- (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
-
- PROCEDURE mkdir ((* EIN/ -- *) REF dir : ARRAY OF CHAR;
- (* EIN/ -- *) mode : modeT ): INTEGER;
-
- VAR res : INTEGER;
- dot : BOOLEAN;
- done : BOOLEAN;
- stack : ADDRESS;
- msize : CARDINAL;
- path0 : StrPtr;
-
- BEGIN
- IF access(dir, fOK) = 0 THEN
- e.errno := e.EEXIST;
- RETURN(-1);
- ELSIF (e.errno <> e.ENOENT) AND (e.errno <> e.ENOTDIR) THEN
- RETURN(-1);
- END;
-
- msize := SLEN(dir) + DINCR;
- memalloc(VAL(sizeT,msize), stack, path0);
- UnixToDos(dir, msize - DINCR, VAL(StrRange,msize), path0, dot, done);
- IF NOT done THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- IF NOT Dcreate(path0, res) THEN
- e.errno := res;
- memdealloc(stack);
- RETURN(-1);
- END;
- IF MiNT THEN
- done := Fchmod(path0, mode, res);
- END;
- memdealloc(stack);
- RETURN(0);
- END mkdir;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE rmdir ((* EIN/ -- *) REF dir : ARRAY OF CHAR ): INTEGER;
-
- VAR res : INTEGER;
- dot : BOOLEAN;
- done : BOOLEAN;
- stack : ADDRESS;
- msize : CARDINAL;
- path0 : StrPtr;
-
- BEGIN
- msize := SLEN(dir) + DINCR;
- memalloc(VAL(sizeT,msize), stack, path0);
- UnixToDos(dir, msize - DINCR, VAL(StrRange,msize), path0, dot, done);
- IF NOT done THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- IF Ddelete(path0, res) THEN
- res := 0;
- ELSE
- IF res = e.eACCDN THEN
- e.errno := e.ENOTEMPTY;
- ELSE
- e.errno := res;
- END;
- res := -1;
- END;
- memdealloc(stack);
- RETURN(res);
- END rmdir;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE chdir ((* EIN/ -- *) REF dir : ARRAY OF CHAR ): INTEGER;
-
- VAR old : CARDINAL;
- res : INTEGER;
- drvs : UNSIGNEDLONG;
- dot : BOOLEAN;
- done : BOOLEAN;
- start : UNSIGNEDWORD;
- stack : ADDRESS;
- msize : CARDINAL;
- path0 : StrPtr;
-
- BEGIN
- msize := SLEN(dir) + DINCR;
- memalloc(VAL(sizeT,msize), stack, path0);
- UnixToDos(dir, msize - DINCR, VAL(StrRange,msize), path0, dot, done);
- IF NOT done THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- (* aktuelles Laufwerk merken, fuer Fehlerfall *)
- old := Dgetdrv();
-
- start := 0;
- IF path0^[0] = 0C THEN
- path0^[0] := DDIRSEP;
- path0^[1] := 0C;
- ELSIF path0^[1] = ':' THEN
- (* neues Laufwerk setzen *)
- drvs := Dsetdrv(tocard(path0^[0]) - 10);
- start := 2;
- END;
-
- (* Pfad ohne Laufwerksangabe setzen *)
- IF Dsetpath(ADDADR(path0, start), res) THEN
- res := 0;
- ELSE
- e.errno := res;
- drvs := Dsetdrv(old);
- res := -1;
- END;
- memdealloc(stack);
- RETURN(res);
- END chdir;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE getcwd ((* EIN/ -- *) buf : StrPtr;
- (* EIN/ -- *) bufsiz : StrRange ): StrPtr;
-
- VAR err : INTEGER;
- dlen : INTEGER;
- xlen : INTEGER;
- str1 : ARRAY [0..0] OF CHAR;
- stack : ADDRESS;
- msize : StrRange;
- path0 : StrPtr;
-
- BEGIN
- msize := bufsiz + XDECR;
- IF NOT MiNT AND (msize < PATHMAX) THEN
- (* mindestens PATHMAX Zeichen Puffer fuer TOS bereitstellen *)
- msize := PATHMAX;
- END;
- memalloc(VAL(sizeT,msize), stack, path0);
- str1[0] := 0C;
- IF CompletePath(CAST(StrPtr,ADR(str1)), msize, path0, dlen, err) THEN
- DosToUnix(path0, bufsiz, buf, dlen, xlen);
- memdealloc(stack);
- IF xlen < VAL(INTEGER,bufsiz) THEN
- RETURN(buf);
- ELSE
- e.errno := e.ERANGE;
- RETURN(NULL);
- END;
- ELSIF err = e.eRANGE THEN
- e.errno := e.ERANGE;
- ELSE
- e.errno := err;
- END;
- memdealloc(stack);
- RETURN(NULL);
- END getcwd;
-
- (*--------------------------------------------------------------------------*)
-
- PROCEDURE opendir ((* EIN/ -- *) REF dir : ARRAY OF CHAR ): DIR;
-
- VAR tdir : TOSDIRPtr;
- err : INTEGER;
- ret : DIR;
- lenDir : INTEGER;
- dot : BOOLEAN;
- done : BOOLEAN;
- drive : ARRAY [0..1] OF CHAR;
- stack : ADDRESS;
- msize : CARDINAL;
- path0 : StrPtr;
- nlen : SIGNEDLONG;
- mdir : MiNTDIRPtr;
-
- BEGIN
- msize := SLEN(dir) + DINCR;
- memalloc(VAL(sizeT,msize), stack, path0);
- UnixToDos(dir, msize - DINCR, VAL(StrRange,msize), path0, dot, done);
- IF NOT done THEN
- memdealloc(stack);
- RETURN(NULL);
- END;
-
- ret := NULL;
- IF MiNT THEN
- IF Dpathconf(path0, 3, nlen) THEN
- (* Feststellen, welche Maximalgroesse Dateinamen haben. *)
- IF nlen > VAL(SIGNEDLONG,TSIZE(PathBuf)) THEN
- nlen := VAL(SIGNEDLONG,TSIZE(MiNTDIRType));
- ELSE
- nlen := VAL(SIGNEDLONG,TSIZE(MiNTDIRType) - TSIZE(PathBuf))
- + nlen
- + LIC(5); (* Fuer abschliessendes Nullbyte & Sicherheit *)
- END;
- ALLOCATE(mdir, nlen);
- IF mdir = NULL THEN
- e.errno := e.ENOMEM; (* vielleicht bessser: EMFILE ? *)
- ELSE
- WITH mdir^ DO
- dsize := VAL(UNSIGNEDLONG,nlen);
- bsize := dsize - VAL(UNSIGNEDLONG,ABS(DIFADR(ADR(dino), ADR(dsize))));
- IF Dopendir(path0, 0, dhandle) THEN
- ret := CAST(DIR,mdir);
- ELSE
- e.errno := INT(dhandle);
- DEALLOCATE(mdir, nlen);
- END;
- END;
- END;
- ELSE
- e.errno := INT(nlen);
- END;
- memdealloc(stack);
- RETURN(ret);
- END;
-
- NEW(tdir);
- IF tdir = NULL THEN
- e.errno := e.ENOMEM; (* vielleicht bessser: EMFILE ? *)
- memdealloc(stack);
- RETURN(NULL);
- END;
-
- WITH tdir^ DO
- (* vollstaendigen Pfad mit Laufwerksangabe merken, damit bei
- * "rewinddir()" das richtige Verzeichnis benutzt wird, falls
- * sich das aktuelle Verzeichnis inzwischen aendert.
- *)
- IF NOT CompletePath(path0,
- PATHMAX + 1, CAST(StrPtr,ADR(dirname)),
- lenDir,
- err)
- THEN
- DISPOSE(tdir);
- tdir := NULL;
- e.errno := err;
- ELSE
- (* alle Dateien finden *)
- IF dirname[VAL(UNSIGNEDWORD,lenDir-1)] = DDIRSEP THEN
- APPEND("*.*", dirname);
- ELSE
- APPEND("\*.*", dirname);
- END;
-
- IF FindFirst(CAST(StrPtr,ADR(dirname)), FINDALL, dta, err) THEN
- status := STARTSEARCH;
- ELSIF err = e.eFILNF THEN
- status := NMFILE;
- ELSE
- DISPOSE(tdir);
- tdir := NULL;
- e.errno := err;
- END;
- END;
- END; (* WITH tdir^ *)
- memdealloc(stack);
- RETURN(CAST(DIR,tdir));
- END opendir;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE readdir ((* EIN/ -- *) dirp : DIR ): DirentPtr;
-
- VAR err : INTEGER;
- tdir : TOSDIRPtr;
- mdir : MiNTDIRPtr;
-
- BEGIN
- IF dirp = NULL THEN
- e.errno := e.EBADF;
- RETURN(NULL);
- END;
-
- IF MiNT THEN
- mdir := CAST(MiNTDIRPtr,dirp);
- WITH mdir^ DO
- IF NOT Dreaddir(VAL(CARDINAL,bsize), dhandle, ADR(dino), err) THEN
- IF err <> e.eNMFIL THEN
- e.errno := err;
- END;
- RETURN(NULL);
- END;
- dirent.dName := CAST(StrPtr,ADR(dname));
- RETURN(CAST(DirentPtr,ADR(dirent)));
- END;
- END;
-
- tdir := CAST(TOSDIRPtr,dirp);
- WITH tdir^ DO
- IF status = NMFILE THEN
- RETURN(NULL);
- ELSIF status = STARTSEARCH THEN
- status := INSEARCH;
- ELSE
- IF NOT FindNext(dta, err) THEN
- IF err = e.eNMFIL THEN
- status := NMFILE;
- ELSE
- e.errno := err;
- END;
- RETURN(NULL);
- END;
- END;
- ASSIGN(dta.name, dname);
- LOWER(dname);
- dirent.dName := CAST(StrPtr,ADR(dname));
- RETURN(CAST(DirentPtr,ADR(dirent)));
- END; (* WITH tdir^ *)
- END readdir;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE rewinddir ((* EIN/ -- *) dirp : DIR );
-
- VAR err : INTEGER;
- tdir : TOSDIRPtr;
- mdir : MiNTDIRPtr;
- done : BOOLEAN;
-
- BEGIN
- IF dirp <> NULL THEN
- IF MiNT THEN
- mdir := CAST(MiNTDIRPtr,dirp);
- done := Drewinddir(mdir^.dhandle, err);
- ELSE
- tdir := CAST(TOSDIRPtr,dirp);
- WITH tdir^ DO
- IF FindFirst(CAST(StrPtr,ADR(dirname)), FINDALL, dta, err) THEN
- status := STARTSEARCH;
- ELSE
- status := NMFILE;
- END;
- END;
- END;
- END;
- END rewinddir;
-
- (*---------------------------------------------------------------------------*)
-
- PROCEDURE closedir ((* EIN/AUS *) VAR dirp : DIR ): INTEGER;
-
- VAR tdir : TOSDIRPtr;
- res : INTEGER;
- mdir : MiNTDIRPtr;
-
- BEGIN
- IF dirp = NULL THEN
- e.errno := e.EBADF;
- RETURN(-1);
- END;
- res := 0;
- IF MiNT THEN
- mdir := CAST(MiNTDIRPtr,dirp);
- IF NOT Dclosedir(mdir^.dhandle, res) THEN
- e.errno := res;
- res := -1;
- END;
- DEALLOCATE(mdir, mdir^.dsize);
- ELSE
- tdir := CAST(TOSDIRPtr,dirp);
- DISPOSE(tdir);
- END;
- dirp := NULL;
- RETURN(res);
- END closedir;
-
- (*--------------------------------------------------------------------------*)
-
- PROCEDURE unlink ((* EIN/ -- *) REF file : ARRAY OF CHAR ): INTEGER;
-
- VAR res : INTEGER;
- done : BOOLEAN;
- dot : BOOLEAN;
- stack : ADDRESS;
- msize : CARDINAL;
- path0 : StrPtr;
-
- BEGIN
- msize := SLEN(file) + DINCR;
- memalloc(VAL(sizeT,msize), stack, path0);
- UnixToDos(file, msize - DINCR, VAL(StrRange,msize), path0, dot, done);
- IF NOT done THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- IF Fdelete(path0, res) THEN
- res := 0;
- ELSE
- e.errno := res;
- res := -1;
- END;
- memdealloc(stack);
- RETURN(res);
- END unlink;
-
- (*--------------------------------------------------------------------------*)
-
- PROCEDURE link ((* EIN/ -- *) REF old : ARRAY OF CHAR;
- (* EIN/ -- *) REF new : ARRAY OF CHAR ): INTEGER;
-
- VAR dot : BOOLEAN;
- done1 : BOOLEAN;
- done2 : BOOLEAN;
- res : INTEGER;
- path01 : StrPtr;
- path02 : StrPtr;
- stack : ADDRESS;
- void : ADDRESS;
- msize1 : CARDINAL;
- msize2 : CARDINAL;
-
- BEGIN
- IF MiNT THEN
- msize1 := SLEN(old) + DINCR;
- msize2 := SLEN(new) + DINCR;
- memalloc(VAL(sizeT,msize1), stack, path01);
- memalloc(VAL(sizeT,msize2), void, path02);
- UnixToDos(old, msize1 - DINCR, VAL(StrRange,msize1), path01, dot, done1);
- UnixToDos(new, msize2 - DINCR, VAL(StrRange,msize2), path02, dot, done2);
- IF NOT (done1 AND done2) THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- IF Flink(path01, path02, res) THEN
- res := 0;
- ELSE
- e.errno := res;
- res := -1;
- END;
- memdealloc(stack);
- RETURN(res);
- ELSE
- e.errno := e.ENOSYS;
- RETURN(-1);
- END;
- END link;
-
- (*--------------------------------------------------------------------------*)
-
- PROCEDURE symlink ((* EIN/ -- *) REF old : ARRAY OF CHAR;
- (* EIN/ -- *) REF new : ARRAY OF CHAR ): INTEGER;
-
- VAR dot : BOOLEAN;
- done1 : BOOLEAN;
- done2 : BOOLEAN;
- res : INTEGER;
- path01 : StrPtr;
- path02 : StrPtr;
- stack : ADDRESS;
- void : ADDRESS;
- msize1 : CARDINAL;
- msize2 : CARDINAL;
-
- BEGIN
- IF MiNT THEN
- msize1 := SLEN(old) + DINCR;
- msize2 := SLEN(new) + DINCR;
- memalloc(VAL(sizeT,msize1), stack, path01);
- memalloc(VAL(sizeT,msize2), void, path02);
- UnixToDos(old, msize1 - DINCR, VAL(StrRange,msize1), path01, dot, done1);
- UnixToDos(new, msize2 - DINCR, VAL(StrRange,msize2), path02, dot, done2);
- IF NOT (done1 AND done2) THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- IF Fsymlink(path01, path02, res) THEN
- res := 0;
- ELSE
- e.errno := res;
- res := -1;
- END;
- memdealloc(stack);
- RETURN(res);
- ELSE
- e.errno := e.ENOSYS;
- RETURN(-1);
- END;
- END symlink;
-
- (*--------------------------------------------------------------------------*)
-
- PROCEDURE readlink ((* EIN/ -- *) REF lname : ARRAY OF CHAR;
- (* EIN/ -- *) buf : StrPtr;
- (* EIN/ -- *) bufsiz : StrRange ): INTEGER;
-
- VAR dot : BOOLEAN;
- done : BOOLEAN;
- res : INTEGER;
- xlen : INTEGER;
- path01 : StrPtr;
- path02 : StrPtr;
- stack : ADDRESS;
- void : ADDRESS;
- msize1 : CARDINAL;
- msize2 : CARDINAL;
-
- BEGIN
- IF MiNT THEN
- msize1 := SLEN(lname) + DINCR;
- msize2 := bufsiz + XDECR;
- memalloc(VAL(sizeT,msize1), stack, path01);
- memalloc(VAL(sizeT,msize2), void, path02);
- UnixToDos(lname, msize1 - DINCR, VAL(StrRange,msize1), path01, dot, done);
- IF NOT done THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- IF NOT Freadlink(msize2, path02, path01, res) AND (res <> e.eRANGE) THEN
- e.errno := res;
- res := -1;
- ELSE
- DosToUnix(path02, bufsiz, buf, res, xlen);
- IF xlen > INT(bufsiz) THEN
- res := INT(bufsiz);
- ELSE
- res := xlen;
- END;
- END;
- memdealloc(stack);
- RETURN(res);
- ELSE
- e.errno := e.ENOSYS;
- RETURN(-1);
- END;
- END readlink;
-
- (*--------------------------------------------------------------------------*)
-
- PROCEDURE rename ((* EIN/ -- *) REF old : ARRAY OF CHAR;
- (* EIN/ -- *) REF new : ARRAY OF CHAR ): INTEGER;
-
- VAR res : INTEGER;
- done1 : BOOLEAN;
- done2 : BOOLEAN;
- dot : BOOLEAN;
- path01 : StrPtr;
- path02 : StrPtr;
- stack : ADDRESS;
- void : ADDRESS;
- msize1 : CARDINAL;
- msize2 : CARDINAL;
-
- BEGIN
- msize1 := SLEN(old) + DINCR;
- msize2 := SLEN(new) + DINCR;
- memalloc(VAL(sizeT,msize1), stack, path01);
- memalloc(VAL(sizeT,msize2), void, path02);
- UnixToDos(old, msize1 - DINCR, VAL(StrRange,msize1), path01, dot, done1);
- UnixToDos(new, msize2 - DINCR, VAL(StrRange,msize2), path02, dot, done2);
- IF NOT (done1 AND done2) THEN
- memdealloc(stack);
- RETURN(-1);
- END;
-
- IF strcmp(path01, path02) = 0 THEN
- (* sonst wird die Datei nachher geloescht... *)
- (* Vergleich erst NACH "UnixToDos()", da unterschiedliche *IX-Namen
- * evtl. auf denselben DOS-Namen abgebildet werden!
- *)
- memdealloc(stack);
- RETURN(0);
- END;
-
- IF access(new, fOK) = 0 THEN
- (* vorhandene Zieldatei zuvor loeschen, falls nicht schreibgeschuetzt,
- * da "GEMDOS" evtl. einen doppelten Name nicht erkennt. Wenn dabei
- * allerdings ein Fehler auftritt, ist die Zieldatei verloren!
- *)
-
- IF NOT Fdelete(path02, res) THEN
- e.errno := res;
- memdealloc(stack);
- RETURN(-1);
- END;
- END;
-
- IF Frename(path01, path02, res) THEN
- res := 0;
- ELSE
- e.errno := res;
- res := -1;
- END;
- memdealloc(stack);
- RETURN(res);
- END rename;
-
- (*==========================================================================*)
-
- BEGIN (* dir *)
- MiNT := MiNTVersion() > 0;
- END dir.
-